#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string>
#include <signal.h>

#include "utils.h"
#include "shmem.h"
#include "timer.h"
//test -n10

using std::string;

// 主/子进程共享数据
static bool running = true;
static CShmem mainsh;
static pid_t main_pid;
static int fork_num = 0;
string semname("asset_query.sem");
string shname("asset_query.shm");
string timername("monitor");
// 主进程的共享内存是一个long型列表，或者叫数组
// 子进程的共享内存储存数据：第一个long是成功笔数，第二个long是失败笔数

static bool monitor_finish = true;
void monitor(int sig, siginfo_t *info, void *ucontext)
{
    if (!monitor_finish)
        return;
    monitor_finish = false;
    timer_t *ptid = CTimer::getTimerId(timername);
    if (ptid == NULL || *ptid != *((timer_t*)(info->si_value.sival_ptr)))
    {
        // 其他 timer 产生的信号
        return;
    }

    long* pidlist = (long*) mainsh.get();

    for( int i = 0; i < fork_num; ++i)
    {
        long pid = *(pidlist + i);
        if (pid <= 0 || pid > 32767)
            continue;

        CShmem sh;
        string name = shname + "." + int2a(int(pid));
        if (!sh.open(name))
        {
            printf("shmem open failed in monitor,pid:%ld",pid);
            break;
        }

        long* suc = (long*)sh.get();
        long* fail = suc + 1;

        printf("pid:%d,suc:%ld,fail:%ld\n",pid,*suc,*fail);
    }

    monitor_finish = true;
}

// 子进程用到的数据 
int subtask();

void exit_child(int sig)
{
    if (sig == SIGINT)
    {
        running = false;
    }
}

void exit_wait()
{
    sigset_t sigs;
    bool bexist = sigismember(&sigs,SIGINT);
    if (!bexist)
    {
        sigaddset(&sigs,SIGINT);
        sigprocmask(SIG_BLOCK,&sigs,NULL);
    }

    int tmpnum = fork_num;
    while(fork_num > 0)
    {
        pid_t pid = wait(NULL);
        // alarm 信号会中断wait
        if (pid < 0)
        {
            // alarm 信号
            if (fork_num == tmpnum)
                continue;
            else
                break;
        }
        printf("child exited:%d\n",pid);
        --fork_num;
    }

    printf("all children exited\n");
}

int main(int _argc, char* _argv[])
{
    for(int i = 1; i < _argc; i ++)
    {
        if(memcmp(_argv[i], "-n", 2) == 0 )
            fork_num =  atol(_argv[i] + 2);
    }

    if (fork_num < 1)
        fork_num = 1;
    if (fork_num > 256)
        fork_num = 256;

    main_pid = getpid();
    string name = shname + "." + int2a(main_pid);
    if (!mainsh.open(name))
    {
        printf("shmem open failed in main process:%d",main_pid);
        return 0;
    }
    long* pidlist = (long*)mainsh.get();
    //*pidlist = main_pid;
    for (int i = 0; i < fork_num; ++i)
    {
        pid_t pid = fork();
        if (pid < 0)
        {
            printf("fork error");
            return 0;
        }
        else if (pid == 0)
        {
            install_sig_handler(SIGINT,exit_child);
            return subtask();
        }
        else
        {
            *(pidlist + i) = pid;
        }
    }

    // 父进程
    pid_t tmppid = getpid();
    if (main_pid == tmppid)
    {
        printf("starting monitor\n");
        CTimer::regTimer(timername,1,0,monitor);
        printf("waiting child\n");
        exit_wait();
    }

    return 0;
}


static const int reqnum = 4;
static char reqs[reqnum][1024] =
{
    // 14条
    "aaa",
    // 1 条
    "bbb",
    // 0 条
    "ccc",
    // 6 条
    "dddd",
};

int subtask()
{
    CShmem sh;
    pid_t self_pid = getpid();
    string myshname = shname + "." + int2a(self_pid);
    if (!sh.open(myshname))
    {
        printf("shmem open failed in process:%d",self_pid);
        return 0;
    }

    long* succount= (long*) sh.get();
    long* failcount = succount + 1;
    *succount = 0;
    *failcount = 0;

    while(running)
    {
        int reqindex = 0;
        for (; reqindex < reqnum; ++reqindex)
        {
            // do something
            *succount += 1;
            *failcount += 1;
            sleep(1);
        }
    }
    return 0;
}









